// ============================================
// TypeScript 高级类型示例
// ============================================

export {}

// 1. 联合类型 (Union Types)
type StringOrNumber = string | number;
type Theme = "light" | "dark" | "auto";

function formatValue(value: StringOrNumber): string {
    if (typeof value === "string") {
        return value.toUpperCase();
    } else {
        return value.toString();
    }
}

let theme: Theme = "dark";
console.log(formatValue("hello"));
console.log(formatValue(42));

// 2. 交叉类型 (Intersection Types)
interface Colorful {
    color: string;
}

interface Circle {
    radius: number;
}

// 交叉类型组合多个类型
type ColorfulCircle = Colorful & Circle;

let cc: ColorfulCircle = {
    color: "red",
    radius: 42
};

// 函数重载的交叉类型
type Combinable = string | number;
type Numeric = number | boolean;
type Universal = Combinable & Numeric; // number

// 3. 类型守卫 (Type Guards)
// typeof 类型守卫
function padLeft(value: string, padding: string | number) {
    if (typeof padding === "number") {
        return Array(padding + 1).join(" ") + value;
    }
    if (typeof padding === "string") {
        return padding + value;
    }
    throw new Error(`Expected string or number, got '${padding}'.`);
}

console.log(padLeft("Hello world", 4));

// instanceof 类型守卫
class Bird {
    fly() {
        console.log("bird fly");
    }
    layEggs() {
        console.log("bird lay eggs");
    }
}

class Fish {
    swim() {
        console.log("fish swim");
    }
    layEggs() {
        console.log("fish lay eggs");
    }
}

function getRandomAnimal(): Bird | Fish {
    return Math.random() > 0.5 ? new Bird() : new Fish();
}

let animal = getRandomAnimal();

if (animal instanceof Bird) {
    animal.fly(); // TypeScript知道这是Bird
} else {
    animal.swim(); // TypeScript知道这是Fish
}

// 4. 自定义类型守卫
function isFish(pet: Fish | Bird): pet is Fish {
    return (pet as Fish).swim !== undefined;
}

if (isFish(animal)) {
    animal.swim();
} else {
    animal.fly();
}

// 5. 可辨识联合 (Discriminated Unions)
interface Square {
    kind: "square";
    size: number;
}

interface Rectangle {
    kind: "rectangle";
    width: number;
    height: number;
}

interface Circle2 {
    kind: "circle";
    radius: number;
}

type Shape = Square | Rectangle | Circle2;

function area(s: Shape): number {
    switch (s.kind) {
        case "square":
            return s.size * s.size;
        case "rectangle":
            return s.height * s.width;
        case "circle":
            return Math.PI * s.radius ** 2;
        default:
            // 完整性检查
            const _exhaustiveCheck: never = s;
            return _exhaustiveCheck;
    }
}

let square: Square = { kind: "square", size: 10 };
console.log(area(square));

// 6. 索引类型 (Index Types)
function pluck<T, K extends keyof T>(o: T, propertyNames: K[]): T[K][] {
    return propertyNames.map(n => o[n]);
}

interface Car {
    manufacturer: string;
    model: string;
    year: number;
}

let car: Car = {
    manufacturer: "Toyota",
    model: "Camry",
    year: 2020
};

let carProps: string[] = pluck(car, ["manufacturer", "model"]);
console.log(carProps);

// keyof 操作符
type CarKeys = keyof Car; // "manufacturer" | "model" | "year"

// 7. 映射类型 (Mapped Types)
// 内置映射类型
type ReadonlyCar = Readonly<Car>;
type PartialCar = Partial<Car>;
type CarManufacturer = Pick<Car, "manufacturer">;
type CarWithoutYear = Omit<Car, "year">;

// 自定义映射类型
type Nullable<T> = {
    [P in keyof T]: T[P] | null;
};

type NullableCar = Nullable<Car>;

let nullableCar: NullableCar = {
    manufacturer: "Honda",
    model: null,
    year: 2021
};

// 8. 条件类型 (Conditional Types)
type TypeName<T> = 
    T extends string ? "string" :
    T extends number ? "number" :
    T extends boolean ? "boolean" :
    T extends undefined ? "undefined" :
    T extends Function ? "function" :
    "object";

type T0 = TypeName<string>; // "string"
type T1 = TypeName<"a">; // "string"
type T2 = TypeName<true>; // "boolean"
type T3 = TypeName<() => void>; // "function"
type T4 = TypeName<string[]>; // "object"

// 分布式条件类型
type BoxedValue<T> = { value: T };
type BoxedArray<T> = { array: T[] };
type Boxed<T> = T extends any[] ? BoxedArray<T[number]> : BoxedValue<T>;

type T20 = Boxed<string>; // { value: string; }
type T21 = Boxed<number[]>; // { array: number[]; }

// 9. 条件类型中的类型推断
type Flatten<T> = T extends (infer U)[] ? U : T;

type T30 = Flatten<string[]>; // string
type T31 = Flatten<number>; // number

// 获取函数返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

type T40 = ReturnType<() => string>; // string
type T41 = ReturnType<(s: string) => void>; // void

// 10. 模板字面量类型 (Template Literal Types)
type World = "world";
type Greeting = `hello ${World}`; // "hello world"

type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
// "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"

// 模板字面量类型的实际应用
type PropEventSource<Type> = {
    on<Key extends string & keyof Type>
        (eventName: `${Key}Changed`, callback: (newValue: Type[Key]) => void): void;
};

interface Person {
    name: string;
    age: number;
}

function makeWatchedObject<Type>(obj: Type): Type & PropEventSource<Type> {
    const listeners: { [key: string]: Function[] } = {};
    
    // 创建代理对象来监听属性变化
    const proxy = new Proxy(obj as any, {
        set(target, property, value) {
            const oldValue = target[property];
            target[property] = value;
            
            // 触发相应的事件
            const eventName = `${String(property)}Changed`;
            if (listeners[eventName]) {
                listeners[eventName].forEach(callback => callback(value, oldValue));
            }
            
            return true;
        }
    });
    
    // 实现 on 方法
    (proxy as any).on = function<Key extends string & keyof Type>(
        eventName: `${Key}Changed`, 
        callback: (newValue: Type[Key]) => void
    ): void {
        if (!listeners[eventName]) {
            listeners[eventName] = [];
        }
        listeners[eventName].push(callback);
    };
    
    return proxy as Type & PropEventSource<Type>;
}

// 使用示例
let person = makeWatchedObject({
    name: "Homer",
    age: 42
});

// 注册事件监听器
person.on("nameChanged", (newName) => {
    console.log(`Name changed to ${newName}`);
});

person.on("ageChanged", (newAge) => {
    console.log(`Age changed to ${newAge}`);
});

// 修改属性会触发事件
person.name = "Marge"; // 输出: Name changed to Marge
person.age = 43;       // 输出: Age changed to 43

// 11. 递归类型
type Json = 
    | string
    | number
    | boolean
    | null
    | Json[]
    | { [key: string]: Json };

const jsonData: Json = {
    name: "John",
    age: 30,
    hobbies: ["reading", "swimming"],
    address: {
        street: "123 Main St",
        city: "Anytown"
    }
};

// 12. 品牌类型 (Branded Types)
type UserId = string & { readonly brand: unique symbol };
type ProductId = string & { readonly brand: unique symbol };

function createUserId(id: string): UserId {
    return id as UserId;
}

function createProductId(id: string): ProductId {
    return id as ProductId;
}

function getUser(id: UserId): void {
    console.log(`Getting user ${id}`);
}

function getProduct(id: ProductId): void {
    console.log(`Getting product ${id}`);
}

let userId = createUserId("user123");
let productId = createProductId("prod456");

getUser(userId); // 正确
// getUser(productId); // 错误：类型不匹配

// 13. 实用工具类型组合
type DeepReadonly<T> = {
    readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};

type DeepPartial<T> = {
    [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

interface Config {
    database: {
        host: string;
        port: number;
        credentials: {
            username: string;
            password: string;
        };
    };
    cache: {
        ttl: number;
        maxSize: number;
    };
}

type ReadonlyConfig = DeepReadonly<Config>;
type PartialConfig = DeepPartial<Config>;

let config: PartialConfig = {
    database: {
        host: "localhost"
        // port 和 credentials 是可选的
    }
};

console.log("=== 高级类型示例完成 ===");